package ggroulette

import (
	"github.com/shopspring/decimal"
	"github.com/tidwall/gjson"
	"wzgames/internal/model/gkindp"
	"wzgames/internal/secure/rng"
	"wzgames/pkg/utils/stringutil"
)

const (
	odd   = "odd"
	even  = "even"
	half1 = "half1"
	half2 = "half2"
	black = "black"
	red   = "red"
	s     = "s"
	h     = "h"
	v     = "v"
	n     = "n"
)

type Gift struct {
	total int32
	arr   []int32
}

func (gf *Gift) Init(cfg *gkindp.MiniRouletteConfig) {
	gf.total = 12
	gf.arr = []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
}

func (gf *Gift) Update(cfg *gkindp.MiniRouletteConfig) {

}

func (gf *Gift) Calculate(servSeed, clientSeed string) int32 {
	num := rng.CalculateHash(servSeed, clientSeed, rng.ChunkSize, 1)[0]
	idx := rng.RouletteResult(num, gf.total)
	if idx >= gf.total {
		idx = gf.total - 1
	}

	return gf.arr[idx]
}

func (gf *Gift) AnalysisChips(chips string, config *gkindp.RouletteGameConfig) ([]*gkindp.RouletteChip, int64, bool) {
	var chipsArr []*gkindp.RouletteChip
	ok := true
	result := gjson.Parse(chips)
	var total int64 = 0
	result.ForEach(func(key, value gjson.Result) bool {
		amt := value.Int()
		if amt == 0 {
			ok = false
			return false
		}
		var sector string
		var idx int32 = 0
		switch key.Str {
		case half1:
			if amt < config.Half1.Min || amt > config.Half1.Max {
				ok = false
				return false
			}
			sector = half1
		case half2:
			if amt < config.Half2.Min || amt > config.Half2.Max {
				ok = false
				return false
			}
			sector = half2
		case odd:
			if amt < config.Odd.Min || amt > config.Odd.Max {
				ok = false
				return false
			}
			sector = odd
		case even:
			if amt < config.Even.Min || amt > config.Even.Max {
				ok = false
				return false
			}
			sector = even
		case red:
			if amt < config.Red.Min || amt > config.Red.Max {
				ok = false
				return false
			}
			sector = red
		case black:
			if amt < config.Black.Min || amt > config.Black.Max {
				ok = false
				return false
			}
			sector = black
		default:
			k := key.Str[:1]
			idx, _ = stringutil.ToInt32(key.Str[1:], -1)
			switch k {
			case h:
				if amt < config.H.Min || amt > config.H.Max || idx < 0 || idx >= config.Sectors.HLen {
					ok = false
					return false
				}
				sector = h
			case v:
				if amt < config.V.Min || amt > config.V.Max || idx < 0 || idx >= config.Sectors.VLen {
					ok = false
					return false
				}
				sector = v
			case s:
				if amt < config.S.Min || amt > config.S.Max || idx < 0 || idx >= config.Sectors.SLen {
					ok = false
					return false
				}
				sector = s
			case n:
				if amt < config.N.Min || amt > config.N.Max || idx < 1 || idx > config.TotalNum {
					ok = false
					return false
				}
				sector = n
			default:
				ok = false
				return false
			}
		}
		chipsArr = append(chipsArr, &gkindp.RouletteChip{Key: key.Str, BetAmt: amt, Sector: sector, Index: idx})
		total += amt

		return true
	})

	if total < config.Total.Min || total > config.Total.Max {
		ok = false
	}

	return chipsArr, total, ok
}

func (gf *Gift) CalcMultiplier(config *gkindp.RouletteGameConfig, result int32, chipsArr []*gkindp.RouletteChip) (decimal.Decimal, decimal.Decimal) {
	l := len(chipsArr)
	betTotal := decimal.NewFromFloat(0.0)
	totalPay := decimal.NewFromFloat(0.0)
	chipEquals := decimal.NewFromFloat(config.ChipEquals)
	for i := 0; i < l; i++ {
		chip := chipsArr[i]
		d := decimal.NewFromInt(chip.BetAmt).Mul(chipEquals)
		betTotal = betTotal.Add(d)
		switch chip.Sector {
		case half1:
			if gf.checkHit(result, config.Sectors.Half1.Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount6)))
			}
		case half2:
			if gf.checkHit(result, config.Sectors.Half2.Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount6)))
			}
		case odd:
			if gf.checkHit(result, config.Sectors.Odd.Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount6)))
			}
		case even:
			if gf.checkHit(result, config.Sectors.Even.Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount6)))
			}
		case red:
			if gf.checkHit(result, config.Sectors.Red.Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount6)))
			}
		case black:
			if gf.checkHit(result, config.Sectors.Black.Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount6)))
			}
		case s:
			if gf.checkHit(result, config.Sectors.S[chip.Index].Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount4)))
			}
		case v:
			if gf.checkHit(result, config.Sectors.V[chip.Index].Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount2)))
			}
		case h:
			if gf.checkHit(result, config.Sectors.H[chip.Index].Vals) {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount2)))
			}
		case n:
			if result == chip.Index {
				totalPay = totalPay.Add(d.Mul(decimal.NewFromFloat(config.PayTableNumAmount1)))
			}
		}
	}

	return betTotal, totalPay
}

func (gf *Gift) checkHit(result int32, nums []int32) bool {
	for i := 0; i < len(nums); i++ {
		if nums[i] == result {
			return true
		}
	}

	return false
}
